11.1 标准库bind函数¶
简介¶
标准库bind函数定义在头文件functional中,我们可以将bind看做是一个通用的函数适配器:它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表:
/*
* 功能: 当我们调用newCallable时, 相当于调用callbale, 并传递给它arg_list指定的参数
*
* newCallable: 新生成的可调用对象
* callable: 原有的可调用对象
* arg_list: 逗号分隔的参数列表, _n表示newCallable中第n个参数
*/
auto newCallable = bind(callable, arg_list);
bind的参数¶
假设f是一个有5个参数的可调用对象,g是一个有2的参数的可调用对象,我们构造下述bind的调用:
using namespace std::placeholders;
auto g = bind(f, a, b, _2, c, _1);
新生成的
g可调用对象有两个参数,分别用占位符_2和_1表示新的可调用对象
g将它自己的参数作为第三个和第五个参数传递给ff的第一个、第二个和第四个参数分别被绑定到给定的值a、b和c上
总结一下:bind调用会将g(_1, _2)映射成f(a, b, _2, c, _1),通过占位符我们也可以重排参数顺序。
绑定引用参数¶
默认情况下bind那些不是占位符的参数被拷贝到bind返回的可调用对象中。与lambda表达式类似,有时候我们希望以引用的方式传递绑定的参数,或是绑定的参数无法拷贝,比如构造一个以引用方式捕获ostream的lambda:
// os是一个局部变量, 引用一个输出流
// c是一个局部变量, 类型为char
for_each(words.begin(), words.end(),
[&os, c](const string &s) { os << s << c; });
我们可以编写一个函数完成这个功能:
ostream &print(ostream &os, const string &s, char c) {
return os << s << c;
}
不过需要注意bind不能拷贝一个ostream,当我们希望传递给bind一个对象而又不拷贝它,就必须用标准库函数ref:
// 错误用法:os无法被拷贝
for_each(words.begin(), words.end(), bind(print, os, _1, ' '));
// 正确用法:使用ref
for_each(words.begin(), words.end(), bind(print, ref(os), _1, ' '));
Tips:标准库中还有一个
cref函数可以生成一个保存const引用的类。